package trunk;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import trunk.config.Config;
import trunk.description.Statistics;
import trunk.parallel.engine.ParaEng;
import trunk.parallel.sameas.ParaSameAsEng;
import trunk.stream.engine.DynGrpEngine;
import trunk.stream.engine.exec.QueryCache;
import trunk.stream.engine.util.Logging;

import com.hp.hpl.jena.query.ARQ;
import com.hp.hpl.jena.query.Dataset;
import com.hp.hpl.jena.query.DatasetFactory;
import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.query.ResultSetFormatter;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.sparql.resultset.ResultSetMem;
import com.hp.hpl.jena.sparql.util.Symbol;

public class query {

	static Long start;
	static Long end;
	static boolean warmup = false;
	
	public static void main(String[] args) throws InterruptedException {
		Config.debug = true;
		query test = new query();
		test.run();
		/*String queryFile = "query.txt";
		String queryString = readQuery(queryFile);
		Query query = QueryFactory.create(queryString);
		
		ResultSet bindings = execute(query);
		ResultSetFormatter.out(new ResultSetMem(bindings),query.getPrefixMapping());
		end = System.nanoTime();
		Long interval = end-start;
		System.out.println(interval.doubleValue()/1000000000);*/
		System.exit(0);
	}
	
	static void processQueryFile() {
		List<List<String>> queries = readQueries("queries.txt");
		for(int i=0;i<queries.size();i++) {
			System.out.println((i+1)+": "+queries.get(i).size());
		}
		
		try {
			BufferedWriter writer = new BufferedWriter(new FileWriter("temp.txt"));
			for(int i=0;i<queries.size();i++) {
				List<String> qs = queries.get(i);
				int j=0;
				for(String s:qs) {
					if(j==20)
						break;
					writer.write(s);
					writer.write("Query "+(i+1)+"#\n");
					writer.newLine();
					writer.flush();
					j++;
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static ResultSet execute(Query query) {
		Config.debug = true;
		start = System.nanoTime();
		Statistics config = new Statistics(new File("stats"));
		end = System.nanoTime();
		Long interval = end-start;
		System.out.println("Stats loaded in "+interval.doubleValue()/1000000000);
		start = System.nanoTime();
		Symbol property = Symbol.create("config");
		ARQ.getContext().set(property, config);
		//ParaEng.register();
		//DynGrpEngine.register();
		//SameAsEng.register();
		ParaSameAsEng.register();
		Model model = ModelFactory.createDefaultModel();
		Dataset dataset = DatasetFactory.create(model);
		
		QueryExecution qe = QueryExecutionFactory.create(query,dataset);
		ResultSet results =qe.execSelect();
		return results;
	}
	
	public static String readQuery(String query) {
		StringBuffer queryString = new StringBuffer();
		File file = new File(query);
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String tempString = null;
	        while ((tempString = reader.readLine()) != null) {
	        	if(tempString.startsWith("#"))
	        		continue;
	        	queryString.append(tempString+" ");
	        }
	        reader.close();
		} catch (FileNotFoundException e) {
			System.out.print("Query file not found.\n");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return queryString.toString();
	}
	
	static public List<List<String>> readQueries(String path) {
		System.out.println("Reading queries...");
		List<List<String>> queries = new ArrayList<List<String>>();
		for(int i =0;i<12;i++) {
			queries.add(new ArrayList<String>());
		}
		
		StringBuffer queryString = new StringBuffer();
		File file = new File(path);
		try {
			BufferedReader reader = new BufferedReader(new FileReader(file));
			String currentline = null;
	        while ((currentline = reader.readLine()) != null) {
	        	//skip comments
	        	if(currentline.startsWith("#") || currentline.isEmpty())
	        		continue;
	        	//store a finished query string
	        	if(currentline.startsWith("Query")) {
	        		String[] parts = currentline.split(" ");
	        		String querynum = parts[1].substring(0, parts[1].length()-1);
	        		int num = Integer.parseInt(querynum);
	        		queries.get(num-1).add(queryString.toString());
	        		queryString = new StringBuffer();
	        		continue;
	        	}
	        	//build up the query string
	        	queryString.append(currentline+"\n");
	        }
	        reader.close();
		} catch (FileNotFoundException e) {
			System.out.print("Query file not found.\n");
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return queries;
	}
	
	private void run() {
		List<Long> querytime = new ArrayList<Long>();
		List<Long> firstresulttime = new ArrayList<Long>();
		List<Integer> resultcount = new ArrayList<Integer>();
		List<Integer> sacount = new ArrayList<Integer>();
		Statistics config = new Statistics(new File("stats"));
		Symbol property = Symbol.create("config");
		ARQ.getContext().set(property, config);
		//ParaEng.register();
		DynGrpEngine.register();
		//SameAsEng.register();
		//DumydumyEng.register();
		//ParaSameAsEng.register();
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		Model model = ModelFactory.createDefaultModel();
		Dataset dataset = DatasetFactory.create(model);
		List<List<String>> queries = readQueries("queries.txt");
		//initiate timer and results count for each query
		for(int i = 0;i<queries.size();i++) {
			querytime.add(0L);
			firstresulttime.add(0L);
			resultcount.add(0);
			sacount.add(0);
		}
		for(int i = 0;i < queries.size();i++) {
			int qnum = i+1;
			if(qnum != 5)
				continue;
			System.out.println("Query " + qnum +" is under testing.");
			//get the number of each queries
			
			List<String> qs = queries.get(i);//get all instances of query i+1
			//qs.remove(3);
			for(int j = 0;j<qs.size();j++) {
				QueryCache.clear();
				String q = qs.get(j);
				
				
				System.out.println(q);//TODO
				long begin = System.nanoTime();
				QueryExecution qe = QueryExecutionFactory.create(q,dataset);
				ResultSet results = qe.execSelect();
				int count = 0;
				if(results.hasNext()) {
					results.next();
					count++;
				}
				long firsttime = System.nanoTime();
				while(results.hasNext()) {
					results.next();
					count++;
				}
				long end = System.nanoTime();
				if(count != 0) {
					System.out.println(count+" results are returned.");
					//System.out.println(q);
					//System.out.println("Query "+qnum+"#");//TODO
				}
				
				
				qe.close();
				//record query time and results count
				firstresulttime.set(i, firstresulttime.get(i)+(firsttime-begin));
				querytime.set(i, querytime.get(i)+(end-begin));
				resultcount.set(i, resultcount.get(i)+count);
				//let the end-points rest for 10sec
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}//TODO
				
				//to warm up
				if(warmup)
					j+=1;
			}
			
			System.out.println("Query "+qnum+" In: "+Logging.getI()+" Out: "+Logging.getO());
			
			/*try {
				Thread.sleep(30000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}*/
		}
		System.out.println("Test is finished.");
		for(int i=0;i<querytime.size();i++) {
			int rounds = queries.get(i).size();
			if(rounds == 0)
				continue;
			System.out.println("Query "+(i+1)+": QT: "+querytime.get(i).doubleValue()/1000000000/rounds +"s; FQT: " + firstresulttime.get(i).doubleValue()/1000000000/rounds + "s; " + "average results count " + resultcount.get(i).doubleValue()/rounds);
			System.out.println("SA count: "+sacount.get(i)/rounds);
		}
	}
	
}